#include "lcd.h"

void LCD_GPIO_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStruct = {0};
	/* GPIO Ports Clock Enable */

	__HAL_RCC_GPIOA_CLK_ENABLE();
	__HAL_RCC_GPIOB_CLK_ENABLE();

	/*Configure GPIO pin : PB12  PB14 */
	GPIO_InitStruct.Pin = GPIO_PIN_12 | GPIO_PIN_14;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

	/*Configure GPIO pin : REST PA8  BLCK PA9 */
	GPIO_InitStruct.Pin = GPIO_PIN_8 | GPIO_PIN_9;
	GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
	GPIO_InitStruct.Pull = GPIO_NOPULL;
	GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
	HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

	/*Configure GPIO pin Output Level  CS PB12 DC PB14 */
	HAL_GPIO_WritePin(GPIOB, GPIO_PIN_12 | GPIO_PIN_14, GPIO_PIN_SET);

	/*Configure GPIO pin Output Level  REST PA8  BLCK PA9 */
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET); // 背光默认关闭
}
/******************************************************************************
	  函数说明：LCD串行数据写入函数
	  入口数据：dat  要写入的串行数据
	  返回值：  无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{

	LCD_CS_Clr();
	HAL_SPI_Transmit(&usr_lcd_spi, &dat, 1, 1000);
	// bsp_spi2_transmit_dma(uint8_t *pTxData, uint16_t Size)
	LCD_CS_Set();
}

/******************************************************************************
	  函数说明：LCD写入数据
	  入口数据：dat 写入的数据
	  返回值：  无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
	LCD_Writ_Bus(dat);
}

/******************************************************************************
	  函数说明：LCD写入数据
	  入口数据：dat 写入的数据
	  返回值：  无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
	LCD_Writ_Bus(dat >> 8);
	LCD_Writ_Bus(dat & 0xff);
}

/******************************************************************************
	  函数说明：LCD写入命令
	  入口数据：dat 写入的命令
	  返回值：  无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
	LCD_DC_Clr(); // 写命令
	LCD_Writ_Bus(dat);
	LCD_DC_Set(); // 写数据
}

/**
 * @brief       设置显示窗口
 * @param       xs:窗口列起始地址
 * @param       ys:坐标行起始地址
 * @param       xe:窗口列结束地址
 * @param       ye:坐标行结束地址
 * @retval      无
 */
void LCD_Address_Set(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye)
{
	if (USE_HORIZONTAL == 0)
	{
		LCD_WR_REG(0x2a); 
	

		LCD_WR_DATA(xs);
		LCD_WR_DATA(xe);

		LCD_WR_REG(0x2b); 
		LCD_WR_DATA(ys + 0x0c);
		LCD_WR_DATA(ye + 0x0c);

		LCD_WR_REG(0x2c); 
	}
	else if (USE_HORIZONTAL == 1)
	{
		LCD_WR_REG(0x2a); 
		LCD_WR_DATA(xs);
		LCD_WR_DATA(xe);

		LCD_WR_REG(0x2b); 
		LCD_WR_DATA(ys + 0x0c);
		LCD_WR_DATA(ye + 0x0c);

		LCD_WR_REG(0x2c); 
	}
	else if (USE_HORIZONTAL == 2)
	{
		LCD_WR_REG(0x2a); 
		LCD_WR_DATA(xs + 0x0c);
		LCD_WR_DATA(xe + 0x0c);

		LCD_WR_REG(0x2b); 
	
	
		LCD_WR_DATA(ys);
		LCD_WR_DATA(ye);

		LCD_WR_REG(0x2c); 
	}
	else
	{
		LCD_WR_REG(0x2a); 
		LCD_WR_DATA(xs + 0x0c);
		LCD_WR_DATA(xe + 0x0c);
		LCD_WR_REG(0x2b); 
		LCD_WR_DATA(ys);
		LCD_WR_DATA(ye);
		LCD_WR_REG(0x2c); 
	}
}

void LCD_Init(void)
{
	LCD_GPIO_Init();

	LCD_RES_Clr();
	
	HAL_Delay(30);
	LCD_RES_Set();
	HAL_Delay(100);
	LCD_BLK_Set();
 	HAL_Delay(100);

	LCD_WR_REG(0x11); 
	HAL_Delay(120); 
	LCD_WR_REG(0x36); 
	if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00);
	else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0);
	else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70);
	else LCD_WR_DATA8(0xA0);

	LCD_WR_REG(0x3A);
	LCD_WR_DATA8(0x05);

	LCD_WR_REG(0xB2);
	LCD_WR_DATA8(0x0C);
	LCD_WR_DATA8(0x0C);
	LCD_WR_DATA8(0x00);
	LCD_WR_DATA8(0x33);
	LCD_WR_DATA8(0x33); 

	LCD_WR_REG(0xB7); 
	LCD_WR_DATA8(0x35);  

	LCD_WR_REG(0xBB);
	LCD_WR_DATA8(0x1A);

	LCD_WR_REG(0xC0);
	LCD_WR_DATA8(0x2C);

	LCD_WR_REG(0xC2);
	LCD_WR_DATA8(0x01);

	LCD_WR_REG(0xC3);
	LCD_WR_DATA8(0x0B);   

	LCD_WR_REG(0xC4);
	LCD_WR_DATA8(0x20);  

	LCD_WR_REG(0xC6); 
	LCD_WR_DATA8(0x0F);    

	LCD_WR_REG(0xD0); 
	LCD_WR_DATA8(0xA4);
	LCD_WR_DATA8(0xA1);

	LCD_WR_REG(0x21); 
	LCD_WR_REG(0xE0);
	LCD_WR_DATA8(0xF0);
	LCD_WR_DATA8(0x00);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x04);
	LCD_WR_DATA8(0x05);
	LCD_WR_DATA8(0x29);
	LCD_WR_DATA8(0x33);
	LCD_WR_DATA8(0x3E);
	LCD_WR_DATA8(0x38);
	LCD_WR_DATA8(0x12);
	LCD_WR_DATA8(0x12);
	LCD_WR_DATA8(0x28);
	LCD_WR_DATA8(0x30);

	LCD_WR_REG(0xE1);
	LCD_WR_DATA8(0xF0);
	LCD_WR_DATA8(0x07);
	LCD_WR_DATA8(0x0A);
	LCD_WR_DATA8(0x0D);
	LCD_WR_DATA8(0x0B);
	LCD_WR_DATA8(0x07);
	LCD_WR_DATA8(0x28);
	LCD_WR_DATA8(0x33);
	LCD_WR_DATA8(0x3E);
	LCD_WR_DATA8(0x36);
	LCD_WR_DATA8(0x14);
	LCD_WR_DATA8(0x14);
	LCD_WR_DATA8(0x29);
	LCD_WR_DATA8(0x32);
	
  LCD_WR_REG(0x11);
  HAL_Delay(120);	
  LCD_WR_REG(0x29); 
}

#define COLOR_FILL_BUFFER_SIZE 240							   // 定义缓冲区大小，可根据实际情况调整
static uint16_t color_fill_buffer[COLOR_FILL_BUFFER_SIZE * 2]; // 静态缓冲区
// GC9307
void Lcd_SendByte(uint8_t dat, LCD_DCType DC)
{

	LCD_CS_Clr();
	if (DC == LCD_DATA)
	{
		LCD_DC_Set();
	}
	else
	{
		LCD_DC_Clr();
	}
	while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
		;
	LCD_CS_Set();
}
void Lcd_SendHalfWord(uint16_t dat)
{
	uint8_t tempdat[2];
	LCD_CS_Clr();
	tempdat[0] = dat >> 8;
	tempdat[1] = dat & 0xFF;
	HAL_SPI_Transmit_DMA(&usr_lcd_spi, tempdat, 2);
	while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
		;
	LCD_CS_Set();
}
void Lcd_SendMulitiByte(uint8_t *dat, uint16_t len)
{
	LCD_CS_Clr();
	LCD_DC_Set();
	HAL_SPI_Transmit_DMA(&usr_lcd_spi, dat, len);
	while (HAL_SPI_GetState(&usr_lcd_spi) == HAL_SPI_STATE_BUSY_TX)
		;
	LCD_CS_Set();
}

/**
 * @brief 填充LCD指定区域为指定颜色
 * @param sx 起始列坐标
 * @param sy 起始行坐标
 * @param ex 结束列坐标
 * @param ey 结束行坐标
 * @param color 颜色数据指针(lv_color_t类型)
 * @note 该函数使用DMA方式分批次传输颜色数据，提高传输效率
 */
void LCD_Color_Fill(u16 sx, u16 sy, u16 ex, u16 ey, lv_color_t *color)
{
	uint32_t y = 0;
	u16 height, width;
	uint32_t total_pixels;

	// 计算填充区域的宽度和高度
	width = ex - sx + 1;
	height = ey - sy + 1;

	total_pixels = width * height; // 计算总像素数

	// 设置LCD显示区域地址范围
	LCD_Address_Set(sx, sy, ex, ey);

	// 分批处理数据(由于内存限制，不能一次性传输所有数据)
	while (total_pixels > 0)
	{
		// 计算本次传输的数据块大小
		uint32_t chunk_size = (total_pixels > COLOR_FILL_BUFFER_SIZE) ? COLOR_FILL_BUFFER_SIZE : total_pixels;

		// 填充缓冲区并处理字节顺序
		for (y = 0; y < chunk_size; y++)
		{
			// 确保颜色字节顺序正确(从lv_color_t格式转换为LCD需要的格式)
			uint16_t pixel = color->full;
			color_fill_buffer[y] = ((pixel & 0xFF) << 8) | (pixel >> 8);

			color++; // 移动到下一个颜色数据
		}

		// 使用DMA发送数据(非阻塞方式，提高传输效率)
		Lcd_SendMulitiByte((uint8_t *)color_fill_buffer, chunk_size * 2);

		total_pixels -= chunk_size; // 更新剩余像素数
	}
}
void LCD_Fill(uint16_t xs, uint16_t ys, uint16_t xe, uint16_t ye, uint16_t color)
{
	uint32_t total_pixels = (xe - xs + 1) * (ye - ys + 1);
	uint32_t i;

	// 设置显示窗口
	LCD_Address_Set(xs, ys, xe, ye);
	uint16_t pixel = color; // 或者可能需要交换字节顺序
	// 如果颜色显示相反，尝试以下修改：
	pixel = ((color & 0xFF) << 8) | (color >> 8);
	// 批量写入颜色数据
	for (i = 0; i < total_pixels; i++)
	{
		LCD_WR_DATA(pixel);
	}
}
